/**
 * @file memlayout.h
 * @date 230426
 * @author xin
 * @brief 记录各个device在内存中的布局、地址位置
 * @version 0.1
 * @status Stable
*/

/*
    qemu -machine virt就如同这样布局
    参考qemu的hw/riscv/virt.c文件：

    0x00001000  --  启动ROM
    0x02000000  --  CLINT
    0x0C000000  --  PLIC
    0x10000000  --  uart0
    0x10001000  --  virtio disk
    0x80000000  --  启动ROM后在机器模式跳到此地址，-kernel在此地址处加载内核
                --  在该地址后的RAM为unused

    内核分布：
    0x80000000  --  entry.S，然后是内核text和data段，然后是end
    end --  内核页分配的区域的开始处
    PHYSTOP --  内核使用RAM的尾部地址
*/

#include "riscv.h"

// 内核和用户使用的页表的开始地址
#define KERNBASE 0x80000000L
// 内核和用户使用的页表的结束地址
#define PHYSTOP (KERNBASE + 128*1024*1024)

// QEMU将UART寄存器放在物理内存的该地址
#define UART0 0x10000000L
#define UART0_IRQ 10

// virtio disk接口地址
#define VIRTIO0 0x10001000
#define VIRTIO0_IRQ 1

// 包括计时器的核本地中断器(CLINT)
#define CLINT 0x2000000L
// 计时器比较器，若MTIME > MTIMECMP，形成时钟中断
#define CLINT_MTIMECMP(hartid) (CLINT + 0x4000 + 8*(hartid))
// 中断计时器MTIME
#define CLINT_MTIME (CLINT + 0xBFF8)

// qemu将平台级中断控制器（PLIC）放置在这儿
#define PLIC            0x0c000000L
#define PLIC_PRIORITY   (PLIC + 0x0)
#define PLIC_PENDING    (PLIC + 0X1000)

// 核hart的Enable寄存器：针对该Hart启动或关闭某路中断源
#define PLIC_MENABLE(hart)      (PLIC + 0x2000 + (hart)*0x100)
// 核hart的Enable寄存器：针对该Hart启动或关闭某路中断源
#define PLIC_SENABLE(hart)      (PLIC + 0x2080 + (hart)*0x100)
// 核hart的Priority寄存器：配置中断源的优先级
#define PLIC_MPRIORITY(hart)    (PLIC + 0x200000 + (hart)*0x2000)
// 核hart的Priority寄存器：配置中断源的优先级
#define PLIC_SPRIORITY(hart)    (PLIC + 0x201000 + (hart)*0x2000)
// 核hart的Claim寄存器/Complete寄存器：获取最高优先级的中断源ID/通知PLIC中断处理结束
#define PLIC_MCLAIM(hart)       (PLIC + 0x200004 + (hart)*0x2000)
// 核hart的Claim寄存器/Complete寄存器：获取最高优先级的中断源ID/通知PLIC中断处理结束
#define PLIC_SCLAIM(hart)       (PLIC + 0x201004 + (hart)*0x2000)

// 对应trap处理代码页的地址，user和kernel地址空间对应的地址数值相同
#define TRAMPOLINE (MAXVA - PGSIZE)

// 映射trampoline下的内核栈空间
// 每个内核栈都无效的保护页包围
#define KSTACK(p)   (TRAMPOLINE - (p + 1) * 2*PGSIZE)

// 用户内存布局
// 0地址开始：
//  文本
//  原始数据和bss段
//  固定大小的栈
//  可扩展的堆
//  ...
//  TRAPFRAME   (p->trapframe，供trampoline使用的数据上下文)
//  TRAMPOLINE  
#define TRAPFRAME   (TRAMPOLINE - PGSIZE)